﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Lipesin.Common;
using CSC.Common.Hosting;

namespace Lipesin.BuildUpdateLaunch
{
	class Program
	{
		static string[] _args = null;

		[STAThread]
		static void Main(string[] args)
		{
			//try
			//{
			_args = args;
			MainWork();
			//}
			//catch (Exception ex)
			//{
			//    Console.WriteLine(ex.ToString());
			//    Console.WriteLine("Нажмите Enter для выхода.");
			//    Console.ReadLine();
			//    return;
			//}
			//if (_copySuccess)
			//{
				
			//}
		}
		static void MainWork()
		{
			System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start();
			TimeSpan totalTime = new TimeSpan(0);
			TimeSpan periodTime = new TimeSpan(0);
			string basePath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
			string baseName = Path.GetFileNameWithoutExtension(System.Reflection.Assembly.GetExecutingAssembly().Location);
			string pathIndex = Path.Combine(basePath, baseName + ".index");
			string pathConfig = Path.Combine(basePath, baseName + ".config");
			string pathState = Path.Combine(basePath, baseName + ".state");
			Config config;
			State state;
			FileIndex index;
			//грузим конфиг
			if (!File.Exists(pathConfig))
			{
				//создаём файл
				config = new Config();
				using (FileStream stream = new FileStream(pathConfig, FileMode.CreateNew))
					config.Write(stream);
				Console.WriteLine("Создан файл конфигурации:");
				Console.WriteLine(pathConfig);
				Console.WriteLine("Проверте, заполнен-ли он правильными значениями, и повторите запуск.");
				Console.ReadLine();
				return;
			}
			using (FileStream stream = new FileStream(pathConfig, FileMode.Open))
				config = new Config(stream);
			//грузим статус
			if (!File.Exists(pathState))
			{
				state = new State();
				using (FileStream stream = new FileStream(pathState, FileMode.CreateNew))
					state.Write(stream);
			}
			using (FileStream stream = new FileStream(pathState, FileMode.Open))
				state = new State(stream);
			totalTime += ShowPeriodTime("Загрузка параметров: ###", stopwatch);

			if (!File.Exists(pathIndex))
			{
				//если индекса нет, то индексируем и запускаем
				index = new FileIndex();
				index.Rebuild(basePath);
				using (FileStream stream = new FileStream(pathIndex, FileMode.CreateNew))
					index.Write(stream);

				totalTime += ShowPeriodTime("Построен новый файловый индекс: ###", stopwatch);
			}
			else
			{
				//если индекс есть, то копируем и запускаем
				using (
					FileStream stream = new FileStream(pathIndex, FileMode.Open))
					index = new FileIndex(stream);
				List<IndexedFileWithSource> filesToCopy;
				DirectoryInfo dir = new DirectoryInfo(Path.Combine(basePath, config.SourcePath));
				System.Text.RegularExpressions.Regex validator = new System.Text.RegularExpressions.Regex(config.FileRegEx);
				filesToCopy = SearchFilesToCopy(dir, index, state.LastWork, validator);
				totalTime += ShowPeriodTime("Поиск файлов для копирования ({0}): ###".F(filesToCopy.Count), stopwatch);
				if (filesToCopy.Count > 0)
				{
					filesToCopy.Sort((item1, item2) => string.Compare(item1.Name, item2.Name));
					int maxNameLen = filesToCopy.Aggregate(0, (max, item) => max < item.Name.Length ? item.Name.Length : max);
					Console.WriteLine("Копирование файлов в базовую директорию {0}".F(basePath));
					foreach (IndexedFileWithSource file in filesToCopy)
						foreach (string destination in file.PathDestination)
						{
							string fullDestination = Path.Combine(destination, file.Name);
							File.Copy(file.PathSource, fullDestination, true);

							Console.WriteLine("{0} {1}".F(file.Name.PadRight(maxNameLen), Path.GetDirectoryName(fullDestination).Substring(basePath.Length + 1)));
							//Console.WriteLine(fullDestination.Substring(basePath.Length + 1));
						}
					totalTime += ShowPeriodTime("Копирование файлов ({0}): ###".F(filesToCopy.Count), stopwatch);
				}
				state.LastWork = DateTime.Now;
			}
			//подсчёт общего времени
			//Console.WriteLine("fin: {0}".F(stopwatch.Elapsed));
			totalTime += stopwatch.Elapsed; stopwatch.Stop();
			Console.WriteLine("Суммарно время работы: {0}".F(totalTime));
			state.AddToToday(totalTime);
			using (FileStream stream = new FileStream(pathState, FileMode.Create))
				state.Write(stream);
			Console.WriteLine();
			Console.WriteLine("Итоговый расход на подготовку сборки по датам:");
			state.TimePerDay.Sort((item1, item2) => DateTime.Compare(item2.Date, item1.Date));
			for (int i = 0; i < 8 && i < (state.TimePerDay.Count); i++)
				Console.WriteLine("{0:dd.MM.yyyy} {1}".F(state.TimePerDay[i].Date, state.TimePerDay[i].Time));
			//запускаем хост
			Console.WriteLine();
			Console.WriteLine("Запуск хоста:");
			PhysicalHostStarter hostStarter = new PhysicalHostStarter(PhysicalHostType.Development);
			hostStarter.Run(_args);
			return;
			////финальная пауза
			//Console.Write("Окно закроется через 10 секунд. ");
			//Console.ForegroundColor -= 1;
			//Console.Write("НАЖМИТЕ ЛЮБУЮ КНОПКУ");
			//Console.ForegroundColor += 1;
			//Console.WriteLine(" для паузы.");

			//bool pressed = false;
			//DateTime timeLimit = DateTime.Now.AddSeconds(10);
			//while (DateTime.Now < timeLimit && !pressed)
			//{
			//    System.Threading.Thread.Sleep(100);
			//    pressed |= Console.KeyAvailable;
			//}
			//if (!pressed) return;
			//Console.ReadKey(true);
			//Console.WriteLine("Пауза. Нажмите Enter для выхода.");
			//Console.ReadLine();
		}
		private static TimeSpan ShowPeriodTime(string message, System.Diagnostics.Stopwatch stopwatch)
		{
			TimeSpan periodTime = stopwatch.Elapsed;
			stopwatch.Restart();
			if (message.Contains("###"))
				message = message.Replace("###", "{0}").F(periodTime);
			Console.WriteLine(message);
			return periodTime;
		}
		//private static void CopyFiles(string sourcePath, FileIndex index, State state)
		//{
		//    List<IndexedFileWithSource> filesToCopy;
		//    DirectoryInfo dir = new DirectoryInfo(sourcePath);
		//    filesToCopy = SearchFilesToCopy(dir, index, state.LastWork);
		//    foreach (IndexedFileWithSource file in filesToCopy)
		//        foreach (string destination in file.PathDestination)
		//        {
		//            string fullDestination = Path.Combine(destination, file.Name);
		//            File.Copy(file.PathSource, fullDestination, true);
		//            Console.WriteLine(fullDestination);
		//        }
		//}
		private static List<IndexedFileWithSource> SearchFilesToCopy(DirectoryInfo directory, FileIndex index, DateTime date, System.Text.RegularExpressions.Regex validator)
		{
			List<IndexedFileWithSource> filesToCopy = new List<IndexedFileWithSource>();
			foreach (DirectoryInfo subdir in directory.GetDirectories())
				filesToCopy.AddRange(SearchFilesToCopy(subdir, index, date, validator));
			foreach (FileInfo file in directory.GetFiles())
			{
				string lowerName = file.Name.ToLower();
				
				if (file.LastWriteTime > date && validator.IsMatch(file.Name))
				{
					IndexedFile ifile = index.Files.Single(item => item.Name == lowerName);
					if (ifile != null && !filesToCopy.Contains(ifile))
						filesToCopy.Add(new IndexedFileWithSource(ifile, file.FullName));
				}
			}
			return filesToCopy;
		}
	}
}
